﻿#region Header

/*
Remote views based on linq
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Collections;
using Sebarf.Diagnostics.Interfaces;
using Sebarf.Services.Interfaces;
using Sebastof.Services.Interfaces;
using Sebastof.Types;

#endregion

namespace Sebastof.Client.Services.Impl {
	/// <summary>
	/// Description of the class
	/// </summary>
	public class ObjectTrackerService : Service, IAppliedChangesOnObjectsCollectorService {
		#region Public Properties

		[ServiceRequest]
		public IObjectTrackerMetadataService ObjectTrackerMetadataService { get; protected set; }

		[ServiceRequest(IsOptional = true)]
		public ICachedDataLocatorService CachedDataLocatorService { get; protected set; }

		#endregion

#if DEBUG
		public event EventHandler Add;
		public event EventHandler Insert;
		public event EventHandler Remove;
		public event EventHandler RemoveAt;
		public event EventHandler Change;

		#region Public Properties

		// public Properties located here

		#endregion

		#region Public Methods

		public ObjectTrackerService(IObjectTrackerMetadataService metaDataService) {
			ObjectTrackerMetadataService = metaDataService;
		}

		public ObjectTrackerService() {
		}

		#endregion

		#region Private Methods

		// private methods located here
		public void DepositeValueChangedEntry(string valueKey, object value, object forObject) {
			var castedobject = (forObject as ISebastofApplicationObject);

			ObjectTrackerMetadataService.AddChangeSet(castedobject,
													   new ChangeSet {
														   oid = castedobject.Id,
														   version = castedobject.GetVersion(),
														   field = valueKey,
														   newvalue = value
													   });
			Check.ArgumentNotNull(castedobject, "castedobject");
			Check.ArgumentNotNull(castedobject.AttachedServiceLocatorService, "castedobject.AttachedContext");
			if (
				!castedobject.AttachedServiceLocatorService.GetRegisteredService<IChangeTrackingStorageService>().
					CurrentDepositedObjectsHaveChanges.Contains(castedobject)) {
				castedobject.AttachedServiceLocatorService.GetRegisteredService<IChangeTrackingStorageService>().
					CurrentDepositedObjectsHaveChanges.Add(castedobject);
			}
			//Logger.WriteDebug(valueKey + ";" + value);
#if DEBUG
			if (Change != null) {
				Change(this, EventArgs.Empty);
			}
#endif
		}

		public void DepositeObjectAddedEntry(object addedValue, object forObject, string valueKey) {
			Logger.WriteDebug("AddItem");

			var castedObjectContainingCollection = (forObject as ISebastofApplicationObject);
			var castedObjectToAdd = (addedValue as ISebastofApplicationObject);

			Check.ArgumentNotNull(castedObjectContainingCollection, "castedobject");
			Check.ArgumentNotNull(castedObjectToAdd, "castednewobject");

			var changeSet = new ChangeCollectionSet();
			changeSet.oidOfCollectionObject = castedObjectContainingCollection.Id;
			changeSet.fieldContainingCollection = valueKey;
			changeSet.operation = ECollectionChangeOperation.Insert;
			changeSet.newvalue = castedObjectToAdd;

			ObjectTrackerMetadataService.AddChangeSet(castedObjectContainingCollection, changeSet);

			foreach (var o in castedObjectToAdd.GetValues()) {
				var cs = new ChangeSet();
				cs.oid = castedObjectToAdd.Id;
				cs.version = castedObjectToAdd.GetVersion();
				cs.field = o.Key;
				cs.newvalue = o.Value;

				ObjectTrackerMetadataService.AddChangeSet(castedObjectToAdd, cs);
				castedObjectContainingCollection.AttachedServiceLocatorService.GetRegisteredService<IChangeTrackingStorageService>()
					.CurrentDepositedObjectsHaveChanges.Add(castedObjectToAdd);
			}

			(castedObjectToAdd as SebastofApplicationObject).AttachedServiceLocatorService =
				castedObjectContainingCollection.AttachedServiceLocatorService;
			//TODO: 
			//if (castednewobject != null)
			//    castedobject.AttachedContext.Attach(castednewobject);
			//castednewobject.AttachedContext = castedobject.AttachedContext;

			castedObjectContainingCollection.AttachedServiceLocatorService.GetRegisteredService<IChangeTrackingStorageService>()
				.CurrentDepositedObjectsHaveCollectionChanges.Add(castedObjectContainingCollection);

#if DEBUG
			if (Add != null) {
				Add(this, EventArgs.Empty);
			}
#endif
		}

		public void DepositeObjectAddedAtEntry(int index, object addedValue, object forObject, string valueKey) {
			Logger.WriteDebug("InsertItem");
#if DEBUG
			if (Insert != null) {
				Insert(this, EventArgs.Empty);
			}
#endif
		}

		public void DepositeObjectRemovedEntry(object removedValue, object forObject, string valueKey) {
			Logger.WriteDebug("RemoveItem");

			DepositeObjectRemovedEntry(
				((forObject as SebastofApplicationObject).GetValue(valueKey) as IList).IndexOf(removedValue), forObject, valueKey);

#if DEBUG
			if (Remove != null) {
				Remove(this, EventArgs.Empty);
			}
#endif
		}

		public void DepositeObjectRemovedAtEntry(int index, object forObject, string valueKey) {
			Logger.WriteDebug("RemoveAtItem");

			var castedObjectContainingCollection = (forObject as ISebastofApplicationObject);

			Check.ArgumentNotNull(castedObjectContainingCollection, "castedobject");

			var changeSet = new ChangeCollectionSet();
			changeSet.oidOfCollectionObject = castedObjectContainingCollection.Id;
			changeSet.fieldContainingCollection = valueKey;
			changeSet.operation = ECollectionChangeOperation.RemoveAt;
			changeSet.indexToOperateOn = index;

			ObjectTrackerMetadataService.AddChangeSet(castedObjectContainingCollection, changeSet);

			castedObjectContainingCollection.AttachedServiceLocatorService.GetRegisteredService<IChangeTrackingStorageService>()
				.CurrentDepositedObjectsHaveCollectionChanges.Add(castedObjectContainingCollection);

#if DEBUG
			if (RemoveAt != null) {
				RemoveAt(this, EventArgs.Empty);
			}
#endif
		}

		// private methods located here
		public void DepositeValueChangedByObjectIdEntry(string valueKey, object value, string forObjectKey, Type objectType,
														 object version) {
			var changeSet = new ChangeSet();
			changeSet.otype = objectType;
			changeSet.oid = forObjectKey;
			changeSet.version = version;
			changeSet.field = valueKey;
			changeSet.newvalue = value;
			if (CachedDataLocatorService != null) {
				if (CachedDataLocatorService.ContainsKey(forObjectKey)) {
					object o = CachedDataLocatorService.GetCachedObject(forObjectKey);
					var oObj = o as SebastofApplicationObject;
					if (oObj != null) {
						oObj.SetValue(valueKey, value);
					}
				}
			}
			ObjectTrackerMetadataService.AddChangeSet(changeSet);
		}

		public void DepositeObjectWasCommited(object obj) {
			ObjectTrackerMetadataService.RemoveChangeSets(obj);
		}

		#endregion

#endif
	}
}